package com.lambo.maven.core.utils.superHttp;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.lambo.maven.core.utils.superHttp.core.SHttpCore;
import com.lambo.maven.core.utils.superHttp.core.SHttpCoreDefault;
import com.lambo.maven.core.utils.superHttp.core.StringUtils;
import com.lambo.maven.core.utils.superHttp.entity.HttpResult;
import com.lambo.maven.core.utils.superHttp.entity.SHttpConfig;
import com.lambo.maven.core.utils.superHttp.utils.ConfigUtil;
import com.lambo.maven.core.utils.superHttp.utils.SHttpUtil;
import com.lambo.maven.core.utils.superHttp.utils.Sock5Util;


/**
 * 统一的 http 请求 集合了所有需要的功能 SuperHttp 基于 Apache HttpClient
 */
public class SHttp implements SHttpI{

    private static Logger logger = LoggerFactory.getLogger(SHttp.class);

    private SHttpConfig config;
    private static String ENCODING_UTF8 = "utf-8";
    
    private RequestConfig proxyRequestConfig;
    private CloseableHttpClient proxyHttpClient;
    private HttpClientContext context = null;

	public void setConfig(SHttpConfig config) {
        this.config = config;
    }

    public RequestConfig getProxyRequestConfig() {
        return this.proxyRequestConfig;
    }

    public void setProxyRequestConfig(RequestConfig proxyRequestConfig) {
        this.proxyRequestConfig = proxyRequestConfig;
    }

    public CloseableHttpClient getProxyHttpClient() {
        return this.proxyHttpClient;
    }

    public void setProxyHttpClient(CloseableHttpClient proxyHttpClient) {
        this.proxyHttpClient = proxyHttpClient;
    }

    public HttpClientContext getContext() {
        return this.context;
    }

    public void setContext(HttpClientContext context) {
        this.context = context;
    }

    public SHttpConfig getConfig() {
        return config;
    }

    public SHttp() {}

    public SHttp(SHttpConfig config) {
        this.config = config;
        String host = config.getProxyHost();
        Integer port = config.getProxyPort();
        proxyHttpClient = SHttpUtil.getHttpClient(config);
        proxyRequestConfig = SHttpUtil.getRequestConfig(config);
        config.setSslsf(SHttpUtil.getSslConent());
        if(config.isSock5Proxy()) {
            context = Sock5Util.getSock5Context(host, port); 
        }
    }

    public void initHttpRequest(HttpRequestBase httpRequest) {
        if(config.isChrome()) {
            SHttpUtil.initChrome(httpRequest);
        }
    }

    public void initHttpResponse(HttpResponse response) {
        if(config.isChrome()) {
            ConfigUtil.init(response);
        }
    }

    public String get(String url, String content, String encoding) {
        return get(url, content, null, encoding);
    }

    public String get(String url, String content, Map<String, String> header, String encoding) {
        HttpResult result = SHttpCoreDefault.byConfig(config).coreGet(this, url, content, header, encoding);
        return result.toString();
    }

    public byte[] getBytes(String url, String content, Map<String, String> header, String encoding) throws IOException {
        HttpResult result = SHttpCoreDefault.byConfig(config).coreGet(this, url, content, header, encoding);
        return result.toByteArray();
    }

    public String get(String url, String param) {
        return get(url, param, ENCODING_UTF8);
    }

    public String get(String url) {
        return get(url, null, ENCODING_UTF8);
    }

    public static String buildParamUrl(Map<String, ?> params) {
        String eq = "=";
        List<String> keyValues = new ArrayList<String>(params.size());
        Set<String> set = params.keySet();
        for (String key : set) {
            keyValues.add(key + eq + params.get(key));
        }
        return StringUtils.join(keyValues, "&");
    }

    public String get(String url, Map<String, ?> param, Map<String, String> header) {
        String paramStr = buildParamUrl(param);
		return get(url, paramStr, header, ENCODING_UTF8);
	}

    public <T> String get(String url, Map<String, ?> param) {
        String paramStr = buildParamUrl(param);
        return get(url, paramStr, ENCODING_UTF8);
    }
    

    public String post(String url, Map<String, String> param){
        return post(url, param, "utf-8");
    }

    // Param 无法满足有序的同时重复key
    public String post(String url, Map<String, ?> param, String encoding){
        return post(url, param, encoding, null);
    }

    public String post(String url, Map<String, ?> param, Map<String, String> header){
        return post(url, param, "utf-8", header);
    }

    public String post(String url, Map<String, ?> param, String encoding, Map<String, String> header){
		List<NameValuePair> pairList = new ArrayList<NameValuePair>(); 
		for(Entry<String, ?> entry : param.entrySet()){
			pairList.add(new BasicNameValuePair(entry.getKey(), String.valueOf( entry.getValue()) ));
		}
        return post(url, pairList, encoding, header);
    }
    
    /**
     * 保证有序同时重复name
     * @param url
     * @param list
     * @param encoding
     * @return
     */
    public String postList(String url, List<String> list, String encoding) {
        List<NameValuePair> pairList = new ArrayList<NameValuePair>(); 
        for(String str : list) {
            if(str.contains("&")) {
                String[] strs = str.split("&");
                String name = strs[0];
                String value = strs[1];
                BasicNameValuePair pair = new BasicNameValuePair(name, value);
                pairList.add(pair);
            } else {
                BasicNameValuePair pair = new BasicNameValuePair(str, "");
                pairList.add(pair);
            }
        }
        return post(url, pairList, encoding, null);
    }

    public SHttpCore getHttpCore() {
        return SHttpCoreDefault.byConfig(config);
    }

    public byte[] postBytes(String url, byte[] bytes) {
        return postBytes(url, bytes, null, null);
    }

    public byte[] postBytes(String url, byte[] bytes, Map<String, String> header, String encoding) {
        ByteArrayEntity arrayEntity = new ByteArrayEntity(bytes);
        arrayEntity.setContentType("application/octet-stream");
        HttpResult result = getHttpCore().corePost(this, url, arrayEntity, header, encoding);
        try {
            return result.toByteArray();
        } catch (RuntimeException e) {
            throw e;
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

    public String postStr(String url, String content, Map<String, String> header, String encoding){
		StringEntity postEntity = new StringEntity(content, encoding);
		return post(url, postEntity, header, encoding);
	}

    public String postJsonStr(String url, String content, Map<String, String> header, String encoding){
        StringEntity postEntity = new StringEntity(content, encoding);
        postEntity.setContentType("application/json");
        return post(url, postEntity, header, encoding);
    }

	public String postStr(String url, String content, String encoding) {
		return postStr(url, content, new HashMap<String, String>(), encoding);
	}

    public String postJsonStr(String url, String content, String encoding) {
        return postJsonStr(url, content, new HashMap<String, String>(), encoding);
    }

	public String postStr(String url, String content) {
        // if(url.contains("10.20")) {
        //     // 内网
        //     return SHttpDefault.getDefault().postStr(url, content);
        // }
		return postStr(url, content, "UTF-8");
    }
    
    public String post(String url, List<NameValuePair> pairList, String encoding, Map<String, String> header) {
        HttpEntity entity;
		try {
            entity = new UrlEncodedFormEntity(pairList, encoding);
            // entity = new UrlEncodedFormEntity(pairList, "utf-8");
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
        return post(url, entity, header, encoding);
    }

    public String post(String url, HttpEntity entity, Map<String, String> header, String encoding){
        try {
            HttpResult result = getHttpCore().corePost(this, url, entity, header, encoding);
            String res = result.toString(encoding);
            return res;
        } catch (RuntimeException e) {
            throw e;
        } catch(Exception e) {
            throw new RuntimeException(e);
        } 
    }

    public HttpResult postResult(String url, HttpEntity entity, Map<String, String> header, String encoding){
        HttpResult result = getHttpCore().corePost(this, url, entity, header, encoding);
        return result;
    }

}